﻿using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.Web.Mvc;
using System.Web.WebPages.Resources;

namespace System.Web.WebPages.Html {
	public partial class HtmlHelper {
		public static IDictionary<string, object> ObjectToDictionary(object instance) {
			IDictionary<string, object> propertyDictionary = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
			if (instance != null) {
				foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(instance)) {
					object obj2 = descriptor.GetValue(instance);
					propertyDictionary.Add(descriptor.Name, obj2);
				}
			}
			return propertyDictionary;
		}

		private void AddErrorClass(TagBuilder tagBuilder, string name) {
			if (!ModelState.IsValidField(name)) {
				tagBuilder.AddCssClass(ValidationInputCssClassName);
			}
		}

		private static object ConvertTo(object value, Type type) {
			Debug.Assert(type != null);
			return UnwrapPossibleArrayType(value, type, CultureInfo.InvariantCulture);
		}

		private static object UnwrapPossibleArrayType(object value, Type destinationType, CultureInfo culture) {
			if (value == null || destinationType.IsInstanceOfType(value)) {
				return value;
			}

			// array conversion results in four cases, as below
			Array valueAsArray = value as Array;
			if (destinationType.IsArray) {
				Type destinationElementType = destinationType.GetElementType();
				if (valueAsArray != null) {
					// case 1: both destination + source type are arrays, so convert each element
					IList converted = Array.CreateInstance(destinationElementType, valueAsArray.Length);
					for (int i = 0; i < valueAsArray.Length; i++) {
						converted[i] = ConvertSimpleType(valueAsArray.GetValue(i), destinationElementType, culture);
					}
					return converted;
				}
				else {
					// case 2: destination type is array but source is single element, so wrap element in array + convert
					object element = ConvertSimpleType(value, destinationElementType, culture);
					IList converted = Array.CreateInstance(destinationElementType, 1);
					converted[0] = element;
					return converted;
				}
			}
			else if (valueAsArray != null) {
				// case 3: destination type is single element but source is array, so extract first element + convert
				if (valueAsArray.Length > 0) {
					value = valueAsArray.GetValue(0);
					return ConvertSimpleType(value, destinationType, culture);
				}
				else {
					// case 3(a): source is empty array, so can't perform conversion
					return null;
				}
			}
			// case 4: both destination + source type are single elements, so convert
			return ConvertSimpleType(value, destinationType, culture);
		}

		private static object ConvertSimpleType(object value, Type destinationType, CultureInfo culture) {
			if (value == null || destinationType.IsInstanceOfType(value)) {
				return value;
			}

			// if this is a user-input value but the user didn't type anything, return no value
			string valueAsString = value as string;
			if (valueAsString != null && valueAsString.Trim().Length == 0) {
				return null;
			}

			TypeConverter converter = TypeDescriptor.GetConverter(destinationType);
			bool canConvertFrom = converter.CanConvertFrom(value.GetType());
			if (!canConvertFrom) {
				converter = TypeDescriptor.GetConverter(value.GetType());
			}
			if (!(canConvertFrom || converter.CanConvertTo(destinationType))) {
				string message = String.Format(CultureInfo.CurrentCulture, WebPageResources.HtmlHelper_NoConverterExists,
					value.GetType().FullName, destinationType.FullName);
				throw new InvalidOperationException(message);
			}

			try {
				object convertedValue = (canConvertFrom) ?
					converter.ConvertFrom(context: null, culture: culture, value: value) :
					converter.ConvertTo(context: null, culture: culture, value: value, destinationType: destinationType);
				return convertedValue;
			}
			catch (Exception ex) {
				string message = String.Format(CultureInfo.CurrentUICulture, WebPageResources.HtmlHelper_ConversionThrew,
					value.GetType().FullName, destinationType.FullName);
				throw new InvalidOperationException(message, ex);
			}
		}
	}
}
